`timescale 1ns/1ps

module async_fifo #(
    parameter FIFO_WIDTH = 8,
    FIFO_DEPTH = 16,
    ADDR_WIDTH = 4
)(
    input   wire                  rclk,
    input   wire                  wclk,
    input   wire                  rst_n,
    input   wire                  wr_en,
    input   wire                  rd_en,
    input   wire [FIFO_WIDTH-1:0] wr_data,
    output  reg  [FIFO_WIDTH-1:0] rd_data,
    output  reg                   empty,
    output  reg                   full
);

// 存储阵列
reg [FIFO_WIDTH-1:0] mem[0:FIFO_DEPTH-1];

// 指针声明
reg [ADDR_WIDTH:0] wr_ptr, rd_ptr;  // 额外1bit用于满判断
wire [ADDR_WIDTH:0] wr_gray, rd_gray;

// 正常同步
reg [ADDR_WIDTH:0] wr2rd_sync1, wr2rd_sync2;
always @(posedge rclk) begin
    wr2rd_sync1 <= wr_gray;
    wr2rd_sync2 <= wr2rd_sync1;
end

// Gray码转换
assign wr_gray = wr_ptr ^ (wr_ptr >> 1);
assign rd_gray = rd_ptr ^ (rd_ptr >> 1);

// 空满生成
always @(*) begin
    `ifdef INJECT_SYNC_ERROR
    empty = (rd_gray == wr2rd_sync);  // 错误：单级同步
    `else
    empty = (rd_gray == wr2rd_sync2); // 正常：两级同步
    `endif
    
    full = (wr_gray == {~(rd_gray[ADDR_WIDTH:ADDR_WIDTH-1]), 
                       rd_gray[ADDR_WIDTH-2:0]});
end

// 写控制
always @(posedge wclk or negedge rst_n) begin
    if(!rst_n) begin
        wr_ptr <= 0;
    end else if(wr_en && !full) begin
        mem[wr_ptr[ADDR_WIDTH-1:0]] <= wr_data;
        wr_ptr <= wr_ptr + 1;
    end
end

// 读控制
always @(posedge rclk or negedge rst_n) begin
    if(!rst_n) begin
        rd_ptr <= 0;
    end else if(rd_en && !empty) begin
        rd_data <= mem[rd_ptr[ADDR_WIDTH-1:0]];
        rd_ptr <= rd_ptr + 1;
    end
end

endmodule